//
// Created by lzc on 2023/1/14.
//

#include "arg.h"
#include "sys/socket.h"
#include "arpa/inet.h"
#include "pthread.h"
#include "sock.h"
#include <unistd.h>
#include "dirent.h"

#define MAX_FILE_LIST 1024
typedef struct fn_args{
    int sockfd;
    ServerArgs args;
}fn_args;

int init_serv(ServerArgs args){
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0){
        printf("create socket fail\n");
        exit(EXIT_FAILURE);
    }

    struct sockaddr_in serv_addr = {};
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(args.port);
    if (!inet_aton(args.listen, &serv_addr.sin_addr)) {
        printf("failed to start fserver: %s is not a valid address\n", args.listen);
        exit(EXIT_FAILURE);
    }

    if (bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr))){
        printf("failed to start fserver: %s:%d already in use\n", inet_ntoa(serv_addr.sin_addr),
               ntohs(serv_addr.sin_port));
        exit(EXIT_FAILURE);
    }

    if (listen(sockfd, 10)) {
        printf("listen fail\n");
        exit(EXIT_FAILURE);
    }
    printf("server listening at %s:%d\n", inet_ntoa(serv_addr.sin_addr),
           ntohs(serv_addr.sin_port) );

    return sockfd;
}

void get_filelist(const char *dirpath, char *files){
    char info[MAX_FILE_LIST] = "file lists:\n";
    DIR *dir;
    struct dirent *dirp;
    if ((dir = opendir(dirpath)) == NULL){
        printf("can not open directory %s\n", dirpath);
        exit(EXIT_FAILURE);
    }
    while ((dirp = readdir(dir)) != NULL) {
        if (strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "..") == 0)
            continue;
        strcat(info, "\t");
        strcat(info, dirp->d_name);
        strcat(info, "\n");
    }
    strcpy(files, info);
}

void* recv_cmd(void* args) {
    fn_args *recv_args = (fn_args *)args;
    int clifd = recv_args->sockfd;
    ServerArgs arg = recv_args->args;
    char *cmd = recStr(clifd);
    if (strcmp(cmd, "list") == 0) {
        char filelist[MAX_FILE_LIST];
        get_filelist(arg.dir, filelist);
        sendStr(clifd, filelist);
    } else if (strcmp(cmd, "dl") == 0) {
        char *filename = recStr(clifd);
        printf("dl: %s\n", filename);
        sendFile(clifd, filename);
    }
    close(clifd);
}

int main(int argc, char *argv[]){
    ServerArgs args;
    parse_serv_args(&args, argc, argv);

    int sockfd = init_serv(args);

    struct sockaddr_in cli_addr;
    socklen_t len;
    int clifd;

    while(1) {
        if ((clifd = accept(sockfd, (struct sockaddr*)&cli_addr, &len)) < 0) {
            printf("accept fail\n");
            exit(EXIT_FAILURE);
        }
        printf("accept client %s:%d\n", inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));

        pthread_t t;
        fn_args cli_arg = {clifd, args};
        pthread_create(&t, NULL, recv_cmd, (void*)&cli_arg);
        pthread_detach(t);
    }

}